import { useState, useEffect, useRef } from 'react'
import { io } from 'socket.io-client'

// 倒计时的自定义 Hook
export function useCountDown(count = 10) {
  // 只要我们发现，某个值的变化，需要在页面上被渲染出来，那么，
  // 这个值必须使用 useState() hook 来进行定义
  const [num, setNum] = useState(count)
  const timer = useRef(null)
  // 按钮是否需要被禁用
  const [isDisabled, setIsDisabled] = useState(false)

  // 调用这个 fn 函数之后，才会开启定时器，开始秒数自减的逻辑
  const fn = () => {
    if (timer.current !== null) return
    // 把按钮的禁用状态打开
    setIsDisabled(true)
    // 开启定时器
    timer.current = setInterval(() => {
      setNum((c) => c - 1)
    }, 1000)
  }

  useEffect(() => {
    if (num <= 0) {
      clearInterval(timer.current)
      // 让倒计时能够被重复执行
      setNum(count)
      // 重置 timer.current null
      timer.current = null
      // 启用按钮
      setIsDisabled(false)
    }
  }, [num, count])

  return [fn, num, isDisabled]
}

// 自定义防抖的 Hook
export function useDebounce(cb, delay = 1500) {
  const timer = useRef(null)
  // 是否正在防抖中
  const [flag, setFlag] = useState(false)

  // 防抖的函数
  const fn = () => {
    if (flag) {
      // 如果正在防抖中，清理上次的延时器
      clearTimeout(timer.current)
      // 重新开启延时器
      startTimeout()
    } else {
      // cb() // 前防抖
      setFlag(true) // 正在防抖中
      // 如果防抖结束了，则允许重新开启延时器
      startTimeout()
    }
  }

  // 开启延时器，计时防抖
  function startTimeout() {
    timer.current = setTimeout(() => {
      // 清理延时器
      clearTimeout(timer.current)
      setFlag(false)
      // 后防抖
      cb()
    }, delay)
  }

  // 性能优化，组件效果时候，清理定时器
  useEffect(() => {
    return () => clearTimeout(timer.current)
  }, [])

  return [fn]
}

// 自定义的防抖的 Hook v2
export function useDebounce2() {
  const timer = useRef(null)
  // 是否正在防抖中...
  const [flag, setFlag] = useState(false)

  // 形参中的 cb 是延时周期结束以后，需要执行的、用户传递进来的回调函数
  function debounce(cb, delay, isFirst) {
    setFlag(true) // 防抖中...
    // 前防抖的条件
    if (timer.current === null && isFirst) {
      cb()
    }
    clearTimeout(timer.current)
    // 把延时器的 id 存储到 timer 中
    timer.current = setTimeout(() => {
      // 只要延时周期结束，就需要执行用户传递进来的回调函数
      !isFirst && cb() // 前防抖
      isFirst && (timer.current = null) // 后防抖
      setFlag(false)
    }, delay)
  }

  // return debounce
  return [debounce, flag]
}

export function useDebounce3() {
  const timer = useRef(null)

  function fd(cb, delay) {
    clearTimeout(timer.current)
    // 先清理上次的延时器，再开下一个延时器
    timer.current = setTimeout(() => {
      cb()
    }, delay)
  }

  return fd
}

// 封装聊天 Socket 的创建
export function useSocket(url, onMessage) {
  // 1. 创建套接字的 ref
  const socket = useRef(null)

  // 副作用函数
  // 如果 useEffect 的依赖项为空数组，则副作用函数仅执行1次（组件首次渲染完毕后）
  useEffect(() => {
    // 初始化 websocket 连接
    // io(服务器的连接地址, 配置对象)
    socket.current = io(url, {
      reconnection: true, // 如果连接不通畅，则会自动重连尝试
      reconnectionAttempts: 5, // 设置重连的次数
      reconnectionDelay: 5000, // 重连的延迟时间 ms
      timeout: 8000 // 超时时间 ms
    })

    // 当客户端与服务器的连接建立后，可以绑定 message 事件，
    // 只要服务器向客户端推送消息了,就会触发 message 事件,
    // 形参中的 msg 就是服务器发送给客户端的消息
    // socket.current.on('message', (msg) => {
    //   const obj = { type: 'AI', msg: msg.replaceAll('{br}', '<br/>') }
    //   setList((prev) => [...prev, obj])
    // })
    socket.current.on('message', onMessage)

    // 在 useEffect 中，return 的这个 fn 就是清理函数
    // return fn
    return () => socket.current.close()
  }, [])

  // 调用此函数，向服务器发送消息
  function emit(value) {
    // 调用 emit 方法发送消息
    // socket.current.emit('发送消息的事件名', 消息内容)
    socket.current.emit('chatWithServer', value)
  }

  return [emit]
}

// 伪代码：调用 useDebounce2
// const fn = useDebounce2()
// fn(() => {
//   console.log('彬哥好帅，不要脸！！')
// }, 1000)

// fn(() => {
//   console.log('彬哥好帅，不要脸！！')
// }, 1000)
